package com.exchange.used.service.impl;

import com.exchange.used.config.constant.K;
import com.exchange.used.config.query.Condition;
import com.exchange.used.config.utils.FormatUtil;
import com.exchange.used.service.RestfulServiceI;
import com.exchange.used.config.utils.SuperSqlBuilder;
import com.exchange.used.config.utils.ContextUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.Id;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

@Service("RestfulService")
public class RestfulService implements RestfulServiceI {

    @Autowired
    JdbcTemplate jdbcTemplate;

    private Class<?> clazz ;
    private JpaRepository repo ;
    private Class idType;


    @Override
    @Transactional
    public boolean executeSaveOrUpdate(String dataTable, List<Map<String, Object>> beans) {
        if(init(dataTable)){
            Object entity ;
            Field field;
            try {
                for(Map<String, Object> bean : beans){
                    entity = this.clazz.newInstance();
                    for (Map.Entry<String, Object> entry : bean.entrySet()) {
                        try {
                            field = clazz.getDeclaredField(entry.getKey());
                            field.setAccessible(true);
                            field.set(entity, FormatUtil.getStdReflectValue(field, entry.getValue().toString()));
                        }catch (Exception e){
                            System.out.println("未找到相应字段：" + entry.getKey());
                        }
                    }
                    this.repo.save(entity);
                }
                return true;
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return false;
    }

    @Override
    public boolean executeDelete(String dataTable, List<Object> ids) {
        if(init(dataTable)) {
            try {
                for(Object id : ids){
                    repo.deleteById(this.idType.cast(id));
                }
                return true;
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return false;
    }


    @Override
    public List<Map<String, Object>> executeQuery(Condition condition) {
        String sql = new SuperSqlBuilder(condition).getSql();
        return jdbcTemplate.queryForList(sql);
    }

    @Override
    public Map<String, Object> getCount(Condition condition) {
        SuperSqlBuilder superSqlBuilder = new SuperSqlBuilder(condition);
        String sql = superSqlBuilder.getCount();
        return jdbcTemplate.queryForList(sql).get(0);
    }

/*
    private Object map2Entity(Map<String, Object> bean){
        Object entity = null;
        Field field;
        for (Map.Entry<String, Object> entry : bean.entrySet()) {
            try {
                entity = this.clazz.newInstance();
                field = clazz.getDeclaredField(entry.getKey());
                if(field != null && entry.getValue() != null) {
                    field.setAccessible(true);
                    field.set(entity, this.idType.cast(entry.getValue()));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return entity;
    }

    private List<Object> listMap2ListEntity(List<Map<String, Object>> beans){
        List<Object> list = new ArrayList<>();
        for(Map<String, Object> bean : beans){
            Object entity = map2Entity(bean);
            list.add(entity);
        }
        return list;
    }
*/


    /**
     * 初始化方法，初始化实体类，对应JPA，主键类型，并检查初始化是否成功
     * @param dataTable 实体名
     * @return 初始化是否成功
     */
    private boolean init(String dataTable){
        try {
            ApplicationContext ctx = ContextUtils.getContext();
            String fullPackName = getFullPackName(dataTable);
            this.repo = (JpaRepository) ctx.getBean(getRepoName(dataTable));
            this.clazz = Class.forName(fullPackName);
            this.idType = getIdType(this.clazz);
            return check();
        } catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }

    private String getRepoName(String dataTable) {
        if (StringUtils.isEmpty(dataTable)) {
            throw new RuntimeException("dataTable can't be null or empty.");
        }
        return dataTable + "Repository";
    }

    private String getFullPackName(String dataTable) {
        if (StringUtils.isEmpty(dataTable)) {
            throw new RuntimeException("dataTable can't be null or empty.");
        }
        return K.ENTITY_PATH + "." + StringUtils.capitalize(dataTable);
    }

    private Class getIdType(Class clazz){
        if (clazz == null) {
            throw new RuntimeException("Can not find the entity.");
        }
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields){
            if(field.getAnnotation(Id.class) != null){
                return field.getType();
            }
        }
        throw new RuntimeException("The entity [" + this.clazz.getName() + "]  has no primary key.");
    }

    private boolean check(){
        return this.clazz != null && this.repo != null && this.idType != null;
    }
}
